<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.1">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/%E6%AD%A6%E6%B1%8932x32.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/%E6%AD%A6%E6%B1%8916x16.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib1/font-awesome/css/all.min.css">
  <link rel="stylesheet" href="/lib1/pace/pace-theme-center-simple.min.css">
  <script src="/lib1/pace/pace.min.js"></script>

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"example.com","root":"/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="前言 React是专注于视图层的解决方案，特点为组件化编程与声明式开发。 声明式与命令式区别：命令式注重过程，开发者需要告诉程序每步要怎么做；声明式注重结果，直接告诉程序要什么。 React基础ReactDOM在React中需要跟真实的DOM打交道都需要通过ReactDOM的API来进行。 但除了render以外，不建议在项目中使用其他API。 12345678910111213141516171">
<meta property="og:type" content="article">
<meta property="og:title" content="react工程师修炼指南（一）">
<meta property="og:url" content="http://example.com/2021/10/10/react/react%E5%B7%A5%E7%A8%8B%E5%B8%88%E4%BF%AE%E7%82%BC%E6%8C%87%E5%8D%97/index.html">
<meta property="og:site_name" content="Technological Blog">
<meta property="og:description" content="前言 React是专注于视图层的解决方案，特点为组件化编程与声明式开发。 声明式与命令式区别：命令式注重过程，开发者需要告诉程序每步要怎么做；声明式注重结果，直接告诉程序要什么。 React基础ReactDOM在React中需要跟真实的DOM打交道都需要通过ReactDOM的API来进行。 但除了render以外，不建议在项目中使用其他API。 12345678910111213141516171">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="http://example.com/image/react%E5%B7%A5%E7%A8%8B%E5%B8%88%E4%BF%AE%E7%82%BC%E6%8C%87%E5%8D%97/image-20211106174458546.png">
<meta property="article:published_time" content="2021-10-10T04:18:39.000Z">
<meta property="article:modified_time" content="2021-11-10T08:39:41.436Z">
<meta property="article:author" content="Li Yudong">
<meta property="article:tag" content="react初学">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="http://example.com/image/react%E5%B7%A5%E7%A8%8B%E5%B8%88%E4%BF%AE%E7%82%BC%E6%8C%87%E5%8D%97/image-20211106174458546.png">

<link rel="canonical" href="http://example.com/2021/10/10/react/react%E5%B7%A5%E7%A8%8B%E5%B8%88%E4%BF%AE%E7%82%BC%E6%8C%87%E5%8D%97/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>react工程师修炼指南（一） | Technological Blog</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">Technological Blog</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">IT小白的成长之旅</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-about">

    <a href="/about/" rel="section"><i class="user fa-fw"></i>关于</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="tags fa-fw"></i>标签<span class="badge">18</span></a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="th fa-fw"></i>分类<span class="badge">14</span></a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="archive fa-fw"></i>归档<span class="badge">95</span></a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
  </div>
</div>

    </div>
  </div>

</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>

  <a href="https://github.com/tiarmor1" class="github-corner" title="Follow me on GitHub" aria-label="Follow me on GitHub" rel="noopener" target="_blank"><svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/10/10/react/react%E5%B7%A5%E7%A8%8B%E5%B8%88%E4%BF%AE%E7%82%BC%E6%8C%87%E5%8D%97/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/author.jpg">
      <meta itemprop="name" content="Li Yudong">
      <meta itemprop="description" content="">
    </span>
    
    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Technological Blog">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          react工程师修炼指南（一）
        </h1>
    
        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
    
              <time title="创建时间：2021-10-10 12:18:39" itemprop="dateCreated datePublished" datetime="2021-10-10T12:18:39+08:00">2021-10-10</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2021-11-10 16:39:41" itemprop="dateModified" datetime="2021-11-10T16:39:41+08:00">2021-11-10</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/react/" itemprop="url" rel="index"><span itemprop="name">react</span></a>
                </span>
            </span>
    
          
    
        </div>
      </header>
    
    
    
    
    <div class="post-body" itemprop="articleBody">
    
      
        <h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p> React是专注于视图层的解决方案，特点为组件化编程与声明式开发。</p>
<p>声明式与命令式区别：命令式注重过程，开发者需要告诉程序每步要怎么做；声明式注重结果，直接告诉程序要什么。</p>
<h1 id="React基础"><a href="#React基础" class="headerlink" title="React基础"></a>React基础</h1><h2 id="ReactDOM"><a href="#ReactDOM" class="headerlink" title="ReactDOM"></a>ReactDOM</h2><p>在React中需要跟真实的DOM打交道都需要通过ReactDOM的API来进行。</p>
<p>但除了render以外，不建议在项目中使用其他API。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*1、render方法是ReactDOM在开发时唯一常用的API，用于将React生成的虚拟DOM生成到虚拟DOM中。</span></span><br><span class="line"><span class="comment">element是React生成的虚拟DOM；container要放置在element的容器中，它必须是一个已经存在的真实DOM节点；</span></span><br><span class="line"><span class="comment">callback是将ReactNode渲染到container之后的回调。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">ReactDOM.render(element, container[, callback]);</span><br><span class="line"></span><br><span class="line">ReactDOM.render(<span class="string">"Hello React"</span>, <span class="built_in">document</span>.querySelector(<span class="string">"#root"</span>), () =&gt; &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"渲染完成"</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">/*这里将“Hello React”这段字符串渲染到了#root这个div;render常用于渲染整个项目的跟组件，使用render时</span></span><br><span class="line"><span class="comment">要注意container中如果有其他内容，就都会被替换掉。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*2、hydrate方法一般配合SSR使用，其作用于ReactDOM复用ReactDOMServer内容时，能够尽可能保留其结构，并补充事件绑定等特性，</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">ReactDOM.hydrate(element, container[, callback])</span><br><span class="line"></span><br><span class="line"><span class="comment">/*3、Component指的是React组件，若其已经渲染到DOM，可通过findDOMNode来获取真实DOM。但其实一般不建议，要获取真实DOM请使用ref</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">ReactDOM.findDOMNode(Component)</span><br><span class="line"></span><br><span class="line"><span class="comment">/*4、container类似于render中的container，一个真实DOM节点。unmountComponentAtNode方法用于container中删除已安装的React组件，并清理其事件处理程序和状态</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">ReactDOM.unmountComponentAtNode(<span class="built_in">document</span>.querySelector(<span class="string">"#root"</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">/*5、createPortal方法用于将节点添加到一个新容器中</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">ReactDOM.createPortal(<span class="xml"><span class="tag">&lt;<span class="name">p</span>&gt;</span> Hello World <span class="tag">&lt;/<span class="name">p</span>&gt;</span></span>, <span class="built_in">document</span>.querySelector(<span class="string">"#box"</span>));</span><br><span class="line"><span class="comment">//App组件的内容在#root中渲染，但App的子组件Child希望在#box中渲染，这是就需要createPortal方法来设置渲染容器。</span></span><br></pre></td></tr></table></figure>

<h2 id="React视图渲染"><a href="#React视图渲染" class="headerlink" title="React视图渲染"></a>React视图渲染</h2><p>当需要用React创建虚拟DOM时，React提供了方法createElement()。属于React对象，type为要创建的标签类型，config参数是设置生成的节点的相关属性，children代表该元素的内容或者子元素。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">React.createElement(type, config, children);</span><br><span class="line"></span><br><span class="line"><span class="comment">//config的类型是一个纯对象，其有两个固定参数key、ref，不能乱用。</span></span><br><span class="line">React.create(<span class="string">"h1"</span>, &#123;</span><br><span class="line">    id: <span class="string">"title"</span>,</span><br><span class="line">    className: <span class="string">"title"</span>,</span><br><span class="line">    title: <span class="string">"前端笔记"</span>,</span><br><span class="line">    style: &#123;</span><br><span class="line">        width: <span class="string">"100px"</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">/*children代表该元素的内容或者子元素，有三种写法</span></span><br><span class="line"><span class="comment">1、children为字符串时，代表在元素中添加文本内容；</span></span><br><span class="line"><span class="comment">2、children为数组时，会将数组中内容展开放入元素；</span></span><br><span class="line"><span class="comment">3、children为ReactElement时，会直接当作元素的子节点进行添加</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure>

<p>上面直接用createElement()来编写视图的方式，从层级结构上十分不清晰，这里我们可以用JSX的方式来做代码编写。但浏览器并不认识JSX的语法扩展，所以需要借助babel.js来对JSX进行编译，使其称为浏览器识别的语法，就是React.createElement()</p>
<h3 id="JSX"><a href="#JSX" class="headerlink" title="JSX"></a>JSX</h3><p>JSX本身是一个值，这个值是一个ReactElement，而非字符串，如果给一个字符串的值，则会被解析为文本内容。因为JSX在解析的时候会被编译，字符串内容会进行转义。</p>
<p>插值表达式：为了让视图与数据进行绑定，就需要使用插值表达式</p>
<p>插值表达式注意事项如下：1、{}中接收一个JS表达式，可以为运算符、变量或函数调用。表达式代表其一定有值返回，而插值代表把表达式计算的值插入至视图；2、{}中接收的是函数调用时，该函数需要有返回值；3、字符串、数字会原样输出；布尔值、空、未定义输出空。但不会有错；数组支持直接输出，默认情况下会将数组连接符，替换成空，然后直接输出；</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//特殊渲染情况：1、列表渲染，将数据批量渲染到JSX，这里需要设置key，确保diff算法</span></span><br><span class="line"><span class="keyword">let</span> arr = [<span class="string">"列表1"</span>, <span class="string">"列表2"</span>, <span class="string">"列表3"</span>];</span><br><span class="line">ReactDOM.render(<span class="xml"><span class="tag">&lt;<span class="name">ul</span>&gt;</span>&#123; arr.map(item =&gt; <span class="tag">&lt;<span class="name">li</span>&gt;</span>&#123;item&#125;<span class="tag">&lt;/<span class="name">li</span>&gt;</span>) &#125;<span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span>, <span class="built_in">document</span>.getElementById(<span class="string">"root"</span>));</span><br><span class="line"><span class="comment">//2、条件渲染：但插值中不能用if语句，这时需要用&amp;&amp;或者||或者三目运算符或者利用判断函数。</span></span><br></pre></td></tr></table></figure>

<p>属性书写：1、所有属性名都使用驼峰命名法；2、如果属性值是字符串并且固定不变，则可以直接写；如果属性值为动态的，则需要用插值表达式；3、有一些特殊的属性名并不能直接用，例如class属性改为className，for属性改为htmlFor，colspan属性改为colSpan。4、style在书写时需注意，它接收的值是一个对象。 </p>
<p>JSX注意事项：1、浏览器并不支持JSX，在使用时需要babel编译；2、JSX不要写成字符串，否则标签会被当做文本直接输出；3、JSX是一个值，在输出时只能有一个顶层标签；3、所有的标签名字都必须小写；4、无论单标签还是双标签，都必须闭合；5、JSX并不是HTML，属性值必须使用驼峰1写法，且style接收的是对象。</p>
<h3 id="组件"><a href="#组件" class="headerlink" title="组件"></a>组件</h3><p>在React中编写组件主要有两种，一种是类组件，一种是函数组件。这里先看看类组件，类组件必须继承自React Component，并且必须有render方法，在render方法中的return中定义的是要渲染的视图。</p>
<p>这里我们介绍下React.StrictMode：用于检查项目中是否有潜在风险的检测工具，类似于严格模式，和Fragment类似，不会渲染任何真实DOM，只是为后代元素触发额外的检查和警告。只在开发模式下运行，能进行以下检测：1、识别具有不安生命周期的组件；2、有关旧式字符串ref用法的警告；3、关于已弃用的findDOMNode用法的警告；4、检测意外的副作用；5、检测遗留的context API。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React <span class="keyword">from</span> <span class="string">'react'</span></span><br><span class="line"><span class="keyword">import</span> ReactDOM <span class="keyword">from</span> <span class="string">'react-dom'</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">App</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span></span>&#123;</span><br><span class="line">    render() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">h1</span>&gt;</span> Hello React <span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">ReactDOM.render(</span><br><span class="line">	&lt;React.StrictMode&gt;</span><br><span class="line">		&lt;App /&gt;</span><br><span class="line">	&lt;<span class="regexp">/React.StrictMode&gt;,</span></span><br><span class="line"><span class="regexp">	document.getElementById('root'));</span></span><br></pre></td></tr></table></figure>

<p>组件的props属性专门用于接收从父组件传递过来的数据，在调用组件时，可以把想传递进去的数据直接加在组件的属性上，然后在组件的内部，通过this.props属性接收传递进来的数据。与Vue类似，就不赘述了。</p>
<h4 id="State"><a href="#State" class="headerlink" title="State"></a>State</h4><p>在React中，组件就是一种状态机，组件会根据状态的不同输出不同UI，state是组件属性的一个属性，该属性的值是一个对象，可以直接用ES6的简写定义，或者要在constructor函数中定义时，由于组件继承自Component，需要加上super()；且constructor的第一个参数是调用该组件时传入的props，需要传递给super，在父类Component中加到this上。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">App</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span></span>&#123;</span><br><span class="line">    <span class="comment">//state = &#123;name: "Hello World"&#125;;这是简写形式</span></span><br><span class="line">    <span class="keyword">constructor</span>(props) &#123;</span><br><span class="line">        <span class="keyword">super</span>(props);</span><br><span class="line">        <span class="keyword">this</span>.state = &#123;</span><br><span class="line">            name: <span class="string">"Hello World"</span></span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">    render() &#123;</span><br><span class="line">        <span class="keyword">let</span> &#123;name, age&#125; = <span class="keyword">this</span>.state;</span><br><span class="line">        <span class="keyword">return</span> (<span class="xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="xml">               <span class="tag">&lt;<span class="name">p</span>&gt;</span><span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line"><span class="xml">               <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>修改state切记不能直接去赋值，因为该操作不会引起视图渲染，需要利用this.setState方法用于更新state的值。调用setState方法后，会根据其传入的值，对state进行修改，根据修改后的state生成新得虚拟DOM。</p>
<p>setState方法在被调用时，只接收两种参数类型，1、为对象，根据对象中的属性，去修改state对应的属性；2、函数，该函数必须有返回值，返回值为对象，代表要修改state中的哪一项。</p>
<p>注意事项：1、调用setState，只需要传入要修改的状态，不需要传入全部状态，setState会自动进行合并；2、setState是一个异步方法，调用后立刻打印会发现state并未改变，跟组件生命周期有关；3、多个setState会被合并，但只引起一次视图渲染，这是为了优化性能，避免多次操作DOM。</p>
<h4 id="通信"><a href="#通信" class="headerlink" title="通信"></a>通信</h4><p>React是单向数据流的设计，信息只能从父级向子级一层层向下传递。1、父级向子级进行通信：利用props即可；2、子组件向父级传递：单项数据流无法从子组件直接传递信息给父组件，但是可以在父组件定义好回调之后，把回调传递给子组件，利用回调向父级传递信息；3、同级组件间传递：同样需要在父组件上进行控制，在父组件上定义好相关的回调，然后传递给子组件，而子组件通过父组件的hi掉进行相关信息传递。</p>
<p>正是由于父组件往往需要管理庞大的数据，react hooks的方式慢慢演进出来。</p>
<p>跨组件通信：在React中，组件嵌套过多的情况，传递数据将变成麻烦的事，在React中专门提供了context用于解决跨组件通信；该用法常见于第三方库。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">调用createContext方法会返回两个组件Provider和Consumer，</span></span><br><span class="line"><span class="comment">Provider组件用于向其后代组件传递数据，把需要传递给子级的数据加给Provider的value属性即可向下传递；</span></span><br><span class="line"><span class="comment">Consumer组件用于接收父祖级传递下来的数据，在Consumer中可以编写一个函数，父祖级传递下来的数据会以参数的形式传递给该函数。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//新建src/context.js文件，在context.js中新建context并导出context、Provider、Consumer:</span></span><br><span class="line"><span class="keyword">import</span> &#123;createContext&#125; <span class="keyword">from</span> <span class="string">"react"</span>;</span><br><span class="line"><span class="keyword">const</span> context = createContext();</span><br><span class="line"><span class="keyword">const</span> &#123;Provider, Consumer&#125; = context;</span><br><span class="line"><span class="keyword">export</span> &#123;Provider, Consumer&#125;;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> context;</span><br><span class="line"></span><br><span class="line"><span class="comment">//修改src/APP.js，在APP组件中调用Provider来传递要传递给子级的数据:</span></span><br><span class="line"><span class="keyword">import</span> React, &#123;Component&#125; <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"><span class="keyword">import</span> Child <span class="keyword">from</span> <span class="string">"./child"</span>;</span><br><span class="line"><span class="keyword">import</span> &#123;Provider&#125; <span class="keyword">from</span> <span class="string">"./context"</span>;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">App</span> <span class="keyword">extends</span> <span class="title">Component</span> </span>&#123;</span><br><span class="line">    render() &#123;</span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">            &lt;Provider value-&#123;&#123;<span class="attr">info</span>:要传递给子级的数据&#125;&#125;&gt;</span><br><span class="line">                &lt;Child /&gt;</span><br><span class="line">            &lt; <span class="regexp">/Provider&gt;</span></span><br><span class="line"><span class="regexp">        &#125;</span></span><br><span class="line"><span class="regexp">    &#125;</span></span><br><span class="line"><span class="regexp">&#125;</span></span><br><span class="line"><span class="regexp">export default App;</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">/</span><span class="regexp">/新建src/</span>child.js文件，在Child中通过Consumer接收父级传递下来的数据</span><br><span class="line"><span class="keyword">import</span> React, &#123;Component&#125; <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123;Consumer&#125; <span class="keyword">from</span> <span class="string">'./context'</span>;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Child</span> <span class="keyword">extends</span> <span class="title">Component</span> </span>&#123;</span><br><span class="line">    render() &#123;</span><br><span class="line">        <span class="keyword">return</span> (</span><br><span class="line">        &lt;Consumer&gt; &#123;(val) =&gt; &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">p</span>&gt;</span>&#123;val.info&#125;<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line">        &#125;&#125; &lt;<span class="regexp">/Consumer&gt;)</span></span><br><span class="line"><span class="regexp">    &#125;</span></span><br><span class="line"><span class="regexp">&#125;</span></span><br><span class="line"><span class="regexp">export default Child;</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">/</span>*在类组件中，除了通过Consumer来接收Provider传递过来的信息之外，还可以通过类的contextType来接收。</span><br><span class="line">然后在组件的context属性中就可以获取到Provider传递过来的数据</span><br><span class="line">*<span class="regexp">/</span></span><br><span class="line"><span class="regexp">import React, &#123;Component&#125; from 'react';</span></span><br><span class="line"><span class="regexp">import context from "./</span>context<span class="string">";</span></span><br><span class="line"><span class="string">class Child extends Component &#123;</span></span><br><span class="line"><span class="string">    static contextType = context;</span></span><br><span class="line"><span class="string">    render() &#123;</span></span><br><span class="line"><span class="string">        return &lt;p&gt;&#123;this.context.info&#125;&lt;/p&gt;</span></span><br><span class="line"><span class="string">    &#125;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">export default Child;</span></span><br></pre></td></tr></table></figure>

<h4 id="生命周期"><a href="#生命周期" class="headerlink" title="生命周期"></a>生命周期</h4><p>生命周期指的是组件从创建到卸载的一个完整过程；React组件的生命周期分为三个阶段：1、挂载阶段：从组件的初始化开始，一直到组件创建完成并渲染到真实的DOM中；2、更新阶段：从组件开始更新，一直监测到组件更新完成并重新渲染完DOM；3、卸载阶段：监听组件从DOM中卸载。</p>
<p>挂载阶段：生命周期顺序为：constructor -&gt; getDerivedStateFromProps -&gt; componentWillMount -&gt; render -&gt; componentDidMount。</p>
<p>1、constructor(props)，在constructor中会初始化该组件；组件为继承Component类，需要加上super；</p>
<p>2、static getDerivedStateFromProps(props, state)：该方法用于从props中获取state，在挂载阶段获取数据并根据props来对state进行修改；其为静态方法，因此不能使用this；且必须有返回值，其返回值是对state的修改，相当于其他地方调用this.setState()时传入的修改对象。该生命周期是根据props来修改state，所以组件初始时一定要定义state属性。</p>
<p>3、componentWillMount：代表组件即将挂载；</p>
<p>4、render：render方法会根据return中的值生成虚拟DOM，然后提交给ReactDOM，渲染真实DOM。</p>
<p>5、componentDidMount：此时组件已经挂载完毕，虚拟DOM已经添加到真实DOM中。</p>
<p>更新阶段：有三个不同的过程，父组件更新引起的当前组件更新 -&gt; 当前组件自己更新 -&gt; forceUpdate。</p>
<p>父组件更新引起的当前组件更新：getDerivedStateFromProps -&gt; shouldComponentUpdate -&gt; render -&gt; getSnaphotBeforeUpdate -&gt; componentDidUpdate</p>
<p>1、getDerivedStateFromProps在更新阶段可以获取到新的props和state，同样返回值是要对state做的修改；</p>
<p>2、shouldComponentUpdate判断组件是否更新；3、render生成新的虚拟DOM；</p>
<p>4、getSnaphotBeforeUpdate：该方法执行在render生成虚拟DOM之后，渲染真实DOM之前，用于获取渲染前的DOM快照。其中的state、props都已经更新，且必须有返回值，该返回值会传递给componentDidUpdate</p>
<p>5、componentDidUpdate：接收getSnaphotBeforeUpdate传递过来的信息。</p>
<p>组件自己更新时，即在组件内部调用了setState，引起当前组件更新。shouldComponentUpdate -&gt; render -&gt; getSnaphotBeforeUpdate -&gt; componentDidUpdate</p>
<p>forceUpdate：React的强制更新组件的方式，当组件依赖的数据不是state时，数据改变了，此时希望视图也进行改变，就可以调用forceUpdate方法。forceUpdate会强制进行视图更新，不会再调用shouldComponentUpdate。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> name = <span class="string">"name"</span>;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">App</span> <span class="keyword">extends</span> <span class="title">Component</span> </span>&#123;</span><br><span class="line">    render() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="xml">            <span class="tag">&lt;<span class="name">p</span>&gt;</span>&#123;name&#125;<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line">        	&lt;button onClick=&#123;()=&gt; &#123;</span><br><span class="line">                name = "新名字";</span><br><span class="line">                this.forceUpdate();</span><br><span class="line"><span class="xml">            &#125;&#125;&gt;更新名字<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="xml">			<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>卸载阶段：组件卸载即把组件从DOM中删除，其生命周期只有componentWillUnmount，用于监听组件即将卸载</p>
<p><img src="/../../image/react%E5%B7%A5%E7%A8%8B%E5%B8%88%E4%BF%AE%E7%82%BC%E6%8C%87%E5%8D%97/image-20211106174458546.png" alt="image-20211106174458546"></p>
<h4 id="ref"><a href="#ref" class="headerlink" title="ref"></a>ref</h4><p>在遇到特殊需求的时候，我们往往需要自己去操作原生DOM节点，比如让文本框获得焦点、使用一些第三方库等。在React中，除了getElementById等原生方法之外，还可以使用React提供的特殊API:ref。</p>
<p>常用的是string ref：当ref绑定在组件上，渲染完成后就可以获取组件实例，通过this.refs来获取。（使用方式时与Vue一致，不再赘述）使用时需要有一些注意事项：1、ref命名需要遵循驼峰命名法；2、单个组件内ref不能重名；3、获取ref时，要在componentDidUpdate和componentDidMount中进行，否则ref是还没有赋值或还没有更新的。</p>
<p>React16之后新增createRef方法：使用createRef创建ref时，需要先把ref绑定在组件的属性或变量中，然后和节点做绑定。获取ref时，需要通过ref的current属性来获取ref中具体的存储内容，示例代码如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Child</span> <span class="keyword">extends</span> <span class="title">Component</span> </span>&#123;</span><br><span class="line">    render() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">p</span>&gt;</span> 子组件内容<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">App</span> <span class="keyword">extends</span> <span class="title">Component</span> </span>&#123;</span><br><span class="line">    parent = createRef();</span><br><span class="line">    child = createRef();</span><br><span class="line">    componentDidMount()&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="keyword">this</span>.parent.current);<span class="comment">//打印真实的DOM节点</span></span><br><span class="line">        <span class="built_in">console</span>.log(<span class="keyword">this</span>.child.current);</span><br><span class="line">    &#125;</span><br><span class="line">    render() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="xml">            <span class="tag">&lt;<span class="name">p</span> <span class="attr">ref</span>=<span class="string">&#123;this.parent&#125;</span>&gt;</span>父组件内容<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line"><span class="xml">        	<span class="tag">&lt;<span class="name">Child</span> <span class="attr">ref</span>=<span class="string">&#123;this.child&#125;</span> /&gt;</span></span></span><br><span class="line"><span class="xml">          <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="事件"><a href="#事件" class="headerlink" title="事件"></a>事件</h4><p>react使用的是一种合成事件机制而非原生的DOM事件，事件名需遵循驼峰命名法，React通过JSX的插值放入一个函数。</p>
<p>其事件处理函数的this默认为undefined，如果希望修改this的化，则需要用bind绑定，或者使用箭头函数。在React中阻止默认事件不能使用return false，必须使用event.preventDefault。</p>
<h4 id="受控组件"><a href="#受控组件" class="headerlink" title="受控组件"></a>受控组件</h4><p>Html中，当用户对表单元素进行操作时，会改变表单的一些内部属性，（如:value、checked、selected等）；这些内部属性也就是该表单控件的一种状态。在React中，想要获取表单的内部状态或者想要控制表单的这些内部状态，可以把组件和表单的状态进行绑定，当组件的state改变时修改表单的状态，或者表单的状态被改变时，再通过setState修改组件的状态，这样九形成了组件对表单控件的控制。</p>
<p>这种操作在React中被称为受控组件。（在Vue上，本质上就是双向绑定）</p>
<p>下面我们以单选框和复选框为例，此控件需要控制checked属性。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">App</span> <span class="keyword">extends</span> <span class="title">Component</span> </span>&#123;</span><br><span class="line">    state = &#123;</span><br><span class="line">        checked: <span class="literal">false</span></span><br><span class="line">    &#125;</span><br><span class="line">    render() &#123;</span><br><span class="line">        <span class="keyword">let</span> &#123;checked&#125; = <span class="keyword">this</span>.state;</span><br><span class="line">        <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line">            &lt;input type="checkbox"</span><br><span class="line">        	checked=&#123;checked&#125;</span><br><span class="line">        	onChange = &#123;(e) =&gt; &#123;</span><br><span class="line">                this.setState(&#123;</span><br><span class="line">                    checked: e.target.checked;</span><br><span class="line">                &#125;)</span><br><span class="line">            &#125;&#125;</span><br><span class="line"><span class="xml">    		/&gt;</span></span><br><span class="line"><span class="xml">		<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">上述案例演示的是受控组件的做法，组件的state和表单控件的状态实时同步。</span></span><br><span class="line"><span class="comment">如果希望state和表单控件的初始值一致，而非实时同步，则可以写成非受控组件的形式</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">App</span> <span class="keyword">extends</span> <span class="title">Component</span> </span>&#123;</span><br><span class="line">    state = &#123;</span><br><span class="line">        val:<span class="string">""</span>,</span><br><span class="line">        checked: <span class="literal">true</span></span><br><span class="line">    &#125;</span><br><span class="line">    render() &#123;</span><br><span class="line">        <span class="keyword">let</span> &#123;val, checked&#125; = <span class="keyword">this</span>.state;</span><br><span class="line">        <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="xml">            <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">defaultValue</span>=<span class="string">&#123;val&#125;/</span>&gt;</span></span></span><br><span class="line"><span class="xml">            <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"checkbox"</span> <span class="attr">defaultChecked</span>=<span class="string">&#123;checked&#125;/</span>&gt;</span></span></span><br><span class="line"><span class="xml">                <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//编写非受控组件时，无须添加onChange事件，但也要注意value和checked，要写defaultValue和defaultChecked</span></span><br></pre></td></tr></table></figure>

<p>children属性时React中一个特殊的API，主要用于传递组件内部要渲染的内容，比如要编写一个弹窗组件，但弹窗的内容是未知的，或者是调用时才需要传递的，这时候就饿可以使用children属性，将弹窗的内容传递进组件。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Popup</span> <span class="keyword">extends</span> <span class="title">Component</span> </span>&#123;</span><br><span class="line">    render() &#123;</span><br><span class="line">        <span class="keyword">let</span> &#123;title, children&#125; = <span class="keyword">this</span>.props;</span><br><span class="line">        <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">div</span> <span class="attr">className</span>=<span class="string">"popup"</span>&gt;</span></span></span><br><span class="line"><span class="xml">            <span class="tag">&lt;<span class="name">h2</span>&gt;</span>&#123;title&#125;<span class="tag">&lt;/<span class="name">h2</span>&gt;</span></span></span><br><span class="line"><span class="xml">        	<span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;children&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">App</span> <span class="keyword">extends</span> <span class="title">Component</span> </span>&#123;</span><br><span class="line">    render() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">Popup</span> <span class="attr">title</span>=<span class="string">"自定义弹窗"</span>&gt;</span></span></span><br><span class="line"><span class="xml">            	<span class="tag">&lt;<span class="name">div</span>&gt;</span>弹窗内容<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="xml">        	<span class="tag">&lt;/<span class="name">Popup</span>&gt;</span></span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//children的用法，在调用时，把要传递的内容写在标签对之间，在子组件中通过props.children就可以接收到父组件传递过来的要渲染的内容</span></span><br></pre></td></tr></table></figure>

<p>dangerouslySetInnerHTML:可以帮助开发者在React元素中直接添加HTML元素，其接收的是一个对象，在对象的html属性中去写要设置的InnerHTML。在React中，如果直接插入带标签的字符串，会把标签也解析为内容的一部分，而不是解析成一个正常的HTML标签。</p>
<h2 id="ReactHooks"><a href="#ReactHooks" class="headerlink" title="ReactHooks"></a>ReactHooks</h2><p>函数式组件即一个函数就是一个组件，函数的第一个参数是父级传递进来的props，返回值是组件要输出的JSX视图。</p>
<p>ReactHooks是React16之后新增的特性：在使用类组件时，会有大量的业务逻辑（如各类接口请求）放在componentDidMount和componentDidUpdate等生命周期函数中，这样会使组件变得复杂且难以维护；且很多逻辑难以通过组件的方式进行复用。</p>
<h3 id="常用Hooks"><a href="#常用Hooks" class="headerlink" title="常用Hooks"></a>常用Hooks</h3><p>Hooks的本质是一类特殊的函数，在React中除了可以自定义Hook以外，还提供了很多内置的Hook。</p>
<p>（1）、useState</p>
<p>useState 可以帮助开发者在函数式组件中使用state，调用该方法时传入state的初始值，该方法会返回一个数组，数组的第0位是state的具体值，而第1位是修改该state的方法，同类组件的setState方法一样，调用该方法会更新State，然后引起视图更新。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//常用方式</span></span><br><span class="line"><span class="keyword">const</span> [state, setState] = useState(initialState);</span><br><span class="line"></span><br><span class="line"><span class="comment">//示例代码 &#123;useState&#125;是模块的命名导出,不加&#123;&#125;的是默认导出 </span></span><br><span class="line"><span class="keyword">import</span> React, &#123;useState&#125; <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">App</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> [name, setName] = useState(<span class="string">"kkb"</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">p</span>&gt;</span>&#123;name&#125;<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line">    	&lt;button onClick=&#123;()=&gt;&#123;</span><br><span class="line">            setName("hello")</span><br><span class="line"><span class="xml">        &#125;&#125;&gt;显示全称<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="xml">	<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> App;</span><br></pre></td></tr></table></figure>

<p>在使用useState时，有下面三个问题要注意：1、useState返回的setState方法同类组件的setState一样，也是一个异步方法，需要组件更新之后state的值才会变成新值；2、useState返回的setState并不具有类组件的setState合并多个state的作用，如果state中有多个state，在更新时则会一起更新；因此我们使用时需要注意只修改某个值则最好用解构赋值。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">App</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> [data, setData] = useState(&#123;<span class="attr">name</span>:<span class="string">"kkb"</span>, <span class="attr">age</span>:<span class="string">"10"</span>&#125;);</span><br><span class="line">    <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">p</span>&gt;</span>&#123;data.name&#125;<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line">    	&lt;button onClick=&#123;() =&gt; &#123;</span><br><span class="line">            setData(&#123;...data,name:"hello"&#125;)</span><br><span class="line"><span class="xml">        &#125;&#125;&gt;显示全称<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="xml">		<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>3、同一个组件中可以使用useState创建多个state；</p>
<p>（2）、useRef</p>
<p>useRef可以看成是createRef的Hook版，使用时先把ref存入变量，然后变量＆DOM节点绑定，使用时通过ref的current属性来获取DOM节点。在函数式组件中，useRef除了用来绑定DOM节点外，还用来保存跨渲染周期的数据，也就是获取组件渲染之前的数据；具体会与useEffect一起使用。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React, &#123;useRef&#125; <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">App</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> elP = useRef();</span><br><span class="line">    <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">p</span> <span class="attr">ref</span>=<span class="string">&#123;elP&#125;</span>&gt;</span>hello world<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line">    	&lt;button onClick=&#123;()=&gt; &#123;</span><br><span class="line">            console.log(elP.cuurent);</span><br><span class="line"><span class="xml">        &#125;&#125;&gt;显示全称<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="xml">	<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> App;</span><br></pre></td></tr></table></figure>

<p>（3）、useEffect</p>
<p>effect翻译为专业术语为副作用，网络请求、DOM操作都是副作用的一种，useEffect就是专门用于处理副作用的。在类组件中，副作用通常在componentDidMount和componentDidUpdate中进行处理，而useEffect就相当于componentDidMount、componentDidUpdate和componentWillUnmount的集合体。useEffect包括两个参数执行时的回调函数和依赖参数，并且回调函数还有一个返回函数。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React, &#123;useState, useEffect&#125; <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Course</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> [course, setCourse] = useState(<span class="string">"课程"</span>);</span><br><span class="line">    <span class="keyword">const</span> [num, setNum] = useState(<span class="number">1</span>);</span><br><span class="line">    useEffect(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">"组件挂载或更新"</span>)；</span><br><span class="line">        <span class="keyword">return</span> <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="built_in">console</span>.log(<span class="string">"清理更新前的一些全局内容，清理时在副作用函数执行之前执行；或检测组件即将卸载"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;, [num]);<span class="comment">//只有num更新时才会执行回调函数</span></span><br><span class="line">    <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line">        &lt;div&gt;选择课程：</span><br><span class="line">    	&lt;select value=&#123;course&#125;</span><br><span class="line">    	onChange=&#123;(&#123;target&#125;) =&gt; &#123; setCourse(target.value);&#125;&#125;&gt;</span><br><span class="line">        &lt;option value="课程1"&gt;课程1&lt;/option&gt;</span><br><span class="line">		&lt;option value="课程2"&gt;课程2&lt;/option&gt;</span><br><span class="line">		&lt;/select&gt;</span><br><span class="line"><span class="xml">	<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">	&lt;div&gt;购买数量：</span><br><span class="line">		&lt;input type="number" value=&#123;num&#125; min=&#123;1&#125;</span><br><span class="line">				onChange=&#123;(&#123;target&#125;) =&gt; &#123; setNum(target.value);&#125;&#125;</span><br><span class="line">          /&gt;</span><br><span class="line"><span class="xml">	<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="xml">	<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">App</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> [show, setShow] = useState(<span class="literal">true</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="xml">        &#123;show?<span class="tag">&lt;<span class="name">Course</span> /&gt;</span>:""&#125;</span></span><br><span class="line">    	&lt;button onClick=&#123;()=&gt; &#123; setShow(!show);&#125;&#125;&gt;</span><br><span class="line">            &#123;show?"隐藏课程"："显示课程"&#125;</span><br><span class="line"><span class="xml">		<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="xml">	<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> App;</span><br></pre></td></tr></table></figure>

<p>useEffect的两个参数：执行时的回调函数、依赖参数。依赖参数其本身是一个数组，在数组中放入要依赖的数据，当这些数据有更新时，就会执行回调函数。整个组件的生命周期流程如下：</p>
<p>组件挂载 -&gt; 执行副作用(回调函数) -&gt; 组件更新 -&gt; 执行清理函数(useEffect返回的函数) -&gt; 执行副作用(回调函数) -&gt; 组件准备卸载 -&gt; 执行清理函数(返还函数) -&gt; 组件卸载。</p>
<p>useEffect就相当于componentDidMount、componentDidUpdate和componentWillUnmount的集合体，如果只想单纯在挂载后、更新后、卸载前其中之一阶段执行，可以参考以下操作：</p>
<p>componentDidMount、componentWillUnmount：想只在挂载后或卸载前执行，可以把依赖参数置为空；这样仅在挂载时触发副作用函数，仅在卸载前执行副作用的返回函数。</p>
<p>componentDidUpdate：只检测更新相对比较麻烦，需要区分更新还是挂载需要检测依赖数据与初始值是否一致。这种情况需要借助useRef的原因在于:ref如果和数据绑定的话，数据更新时ref并不会自动更新，这样就可以获取到更新前的数据。下例代码中，可以看到useEffect模拟的各个阶段，且一个组件中拥有多个useEffect的实例。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Course</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> [course, setCourse] = useState(<span class="string">"Hello"</span>);</span><br><span class="line">    <span class="keyword">const</span> [num, setNum] = useState(<span class="number">1</span>);</span><br><span class="line">    <span class="keyword">let</span> prevCourse = useRef(course);</span><br><span class="line">    <span class="keyword">let</span> prevNum = useRef(num);</span><br><span class="line">    useEffect(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">"组件挂载阶段"</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="built_in">console</span>.log(<span class="string">"组件卸载之前"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;, []);<span class="comment">//传入依赖参数为空数组，这样就只会在挂载和卸载阶段调用，而组件更新阶段不会调用该副作用</span></span><br><span class="line">    useEffect(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (course != prevCourse.current || num != prevNum.current) &#123;</span><br><span class="line">            <span class="comment">//如果当前值和上次值不一样，则待变组件有更新</span></span><br><span class="line">            <span class="built_in">console</span>.log(<span class="string">"组件更新"</span>);</span><br><span class="line">            <span class="comment">//这里注意，ref不会自动进行更新，需要手动更新</span></span><br><span class="line">            prevCourse.current = course;</span><br><span class="line">            prevNum.current = num;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;, [course, num]);</span><br><span class="line">    <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span></span><br><span class="line">        &lt;div&gt;选择课程：</span><br><span class="line">    	&lt;select value= &#123;course&#125; onChange=&#123;(&#123;target&#125;) =&gt; &#123;</span><br><span class="line">            setCourse(target.value);</span><br><span class="line">        &#125;&#125;&gt; </span><br><span class="line">        	&lt;option value="课程1"&gt;课程1&lt;/option&gt;</span><br><span class="line">			&lt;option value="课程2"&gt;课程2&lt;/option&gt;</span><br><span class="line">		&lt;/select&gt;</span><br><span class="line"><span class="xml">	<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">	&lt;div&gt;购买数量:</span><br><span class="line">    	&lt;input type="number" value=&#123;num&#125; min=&#123;1&#125;</span><br><span class="line">				onChange=&#123;(&#123;target&#125;) =&gt; &#123;</span><br><span class="line">                    setNum(target.value);</span><br><span class="line">                &#125;&#125;</span><br><span class="line">                /&gt;</span><br><span class="line"><span class="xml">		<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="xml">	<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="自定义Hook"><a href="#自定义Hook" class="headerlink" title="自定义Hook"></a>自定义Hook</h3><p>Hooks的使用规则如下：1、只能在函数式组件和自定义Hooks之中调用Hooks，普通函数或者类组件中不能使用Hooks；2、只能在函数的第一层调用Hooks。如果函数中还嵌套了流程控制语句如if或者for，这些地方是不能再调用Hooks的，当然函数之中嵌套了子函数，子函数中一样也不能使用Hooks。Hooks的设计极度依赖其定义时的顺序，如组件更新时Hooks的调用顺序改变了，就会出现不可预知的问题。Hooks的使用也是为了保证Hooks调用顺序的稳定性，为此React提供一个ESLint plugin来做静态代码检测。</p>
<p>除了可以使用React定义好的Hooks之外，React也允许开发者自己定义Hook。前文说过一些简单的单纯逻辑难以通过组件去复用，而自定义Hook就可以很完美地去解决这个问题。可以把一些二需要重复使用的逻辑自定义成Hook。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">useScrollY</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> [scrollY, setScrollY] = useState(<span class="number">0</span>);</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">scroll</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        setScrollY(<span class="built_in">window</span>.scrollY);</span><br><span class="line">    &#125;</span><br><span class="line">    useEffect(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">window</span>.addEventListener(<span class="string">"scroll"</span>, scroll);</span><br><span class="line">        <span class="keyword">return</span> <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="built_in">window</span>.removeEventListener(<span class="string">"scroll"</span>, scroll);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;, []);</span><br><span class="line">    <span class="keyword">return</span> scrollY;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">App</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> scrollY = useScrollY();</span><br><span class="line">    <span class="keyword">return</span> <span class="xml"><span class="tag">&lt;<span class="name">div</span> <span class="attr">style</span>=<span class="string">&#123;&#123;border:</span>"<span class="attr">1px</span> <span class="attr">solid</span> #<span class="attr">000</span>", <span class="attr">height:</span>"<span class="attr">1500px</span>"&#125;&#125;&gt;</span></span></span><br><span class="line"><span class="xml">        <span class="tag">&lt;<span class="name">p</span> <span class="attr">style</span>=<span class="string">&#123;&#123;position:</span>"<span class="attr">fixed</span>", <span class="attr">left:0</span>, <span class="attr">top:0</span>&#125;&#125;当前滚动条未知是：&#123;<span class="attr">scrollY</span>&#125;&gt;</span><span class="tag">&lt;/<span class="name">p</span>&gt;</span></span></span><br><span class="line"><span class="xml">		<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>上例中useScrollY就是一个自定义Hook，在useScrollY中，定义好了顿东条未知的整个逻辑处理，将来需要使用滚动条位置时，直接调用useScrollY即会返回一个状态，并且该状态会根据滚动条的位置变化而进行更新。</p>
<p>这样就可以极大第精简组件的逻辑，使组件中的代码一目了然，并且其他地方有响应需求也可以重复调用useScrollY。在使用自定义Hook时，同样需要遵守Hooks的使用规则，另外要注意React要求自定义Hook的命名也必须以use开始，以区别于其他函数。</p>

    </div>
    
    
    
    
    <div>
      
        <div>
    
        <div style="text-align:center;color: #ccc;font-size:14px;">-------------本文结束<i class="fa fa-paw"></i>感谢您的阅读-------------</div>
    
</div>

      
    </div>
        <div class="reward-container">
  <div>坚持原创技术分享，您的支持将鼓励我继续创作！</div>
  <button onclick="var qr = document.getElementById('qr'); qr.style.display = (qr.style.display === 'none') ? 'block' : 'none';">
    打赏
  </button>
  <div id="qr" style="display: none;">
      
      <div style="display: inline-block;">
        <img src="/images/alipay.png" alt="Li Yudong 支付宝">
        <p>支付宝</p>
      </div>

  </div>
</div>

        

<div>
<ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者： </strong>Li Yudong
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="http://example.com/2021/10/10/react/react%E5%B7%A5%E7%A8%8B%E5%B8%88%E4%BF%AE%E7%82%BC%E6%8C%87%E5%8D%97/" title="react工程师修炼指南（一）">http://example.com/2021/10/10/react/react工程师修炼指南/</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" rel="noopener" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！
  </li>
</ul>
</div>

    
      <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/react%E5%88%9D%E5%AD%A6/" rel="tag"># react初学</a>
          </div>
    
        

    
        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2021/10/03/webgl/three.js%E7%B2%92%E5%AD%90%E4%B8%8E%E7%B2%BE%E7%81%B5/" rel="prev" title="three.js粒子">
      <i class="fa fa-chevron-left"></i> three.js粒子
    </a></div>
      <div class="post-nav-item">
    <a href="/2021/10/14/node/node.js%E6%A8%A1%E5%9D%97/" rel="next" title="nodejs模块">
      nodejs模块 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#前言"><span class="nav-number">1.</span> <span class="nav-text">前言</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#React基础"><span class="nav-number">2.</span> <span class="nav-text">React基础</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#ReactDOM"><span class="nav-number">2.1.</span> <span class="nav-text">ReactDOM</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#React视图渲染"><span class="nav-number">2.2.</span> <span class="nav-text">React视图渲染</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#JSX"><span class="nav-number">2.2.1.</span> <span class="nav-text">JSX</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#组件"><span class="nav-number">2.2.2.</span> <span class="nav-text">组件</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#State"><span class="nav-number">2.2.2.1.</span> <span class="nav-text">State</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#通信"><span class="nav-number">2.2.2.2.</span> <span class="nav-text">通信</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#生命周期"><span class="nav-number">2.2.2.3.</span> <span class="nav-text">生命周期</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#ref"><span class="nav-number">2.2.2.4.</span> <span class="nav-text">ref</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#事件"><span class="nav-number">2.2.2.5.</span> <span class="nav-text">事件</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#受控组件"><span class="nav-number">2.2.2.6.</span> <span class="nav-text">受控组件</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#ReactHooks"><span class="nav-number">2.3.</span> <span class="nav-text">ReactHooks</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#常用Hooks"><span class="nav-number">2.3.1.</span> <span class="nav-text">常用Hooks</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#自定义Hook"><span class="nav-number">2.3.2.</span> <span class="nav-text">自定义Hook</span></a></li></ol></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="Li Yudong"
      src="/images/author.jpg">
  <p class="site-author-name" itemprop="name">Li Yudong</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">95</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">14</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">18</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/tiarmor1" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;tiarmor1" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="mailto:1157019137@qq.com" title="E-Mail → mailto:1157019137@qq.com" rel="noopener" target="_blank"><i class="fa fa-envelope fa-fw"></i>E-Mail</a>
      </span>
  </div>
  <div class="cc-license motion-element" itemprop="license">
    <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" class="cc-opacity" rel="noopener" target="_blank"><img src="/images/cc-by-nc-sa.svg" alt="Creative Commons"></a>
  </div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 2020 – 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Li Yudong</span>
</div>

        








      </div>
    </footer>
  </div>

  
  
  <script color='0,0,0' opacity='0.5' zIndex='-1' count='150' src="/lib1/canvas-nest/canvas-nest.min.js"></script>
  <script src="/lib1/anime.min.js"></script>
  <script src="/lib1/velocity/velocity.min.js"></script>
  <script src="/lib1/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  




  
<script src="/js/local-search.js"></script>













  

  

  
   <canvas class="fireworks" style="position: fixed;left: 0;top: 0;z-index: 1; pointer-events: none;" ></canvas> 
   <script type="text/javascript" src="//cdn.bootcss.com/animejs/2.2.0/anime.min.js"></script> 
   <script type="text/javascript" src="/js/fireworks.js"></script>
  
</body>
</html>

